package oop.ex3.usercommands;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.TreeSet;

import oop.ex3.filemanager.FileManager;
import oop.ex3.protocol.WantAllFiles;
import oop.ex3.protocol.WantServers;
import oop.ex3.sharedclasses.IPaddress;

public class DirAllFiles extends UserMessage {
	public static final String COMMAND="DIRALLFILES";
	
	private HashSet<String> _fileNames;
	private LinkedList<IPaddress> _usedNameServers;
	private LinkedList<IPaddress> _knownNameServers;
	
	public DirAllFiles(FileManager fileManager) {
		super(fileManager);
		_fileNames = new HashSet<String>();
		this._usedNameServers = new LinkedList<IPaddress>();
		this._knownNameServers = fileManager.getNameServerList();
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean run() {
		
		WantServers serverAsker = new WantServers();
		WantAllFiles fileAsker = new WantAllFiles();
		for (IPaddress nameServer : _knownNameServers){
			if (wasNameServerUsed(nameServer)){
				continue;
			}
			addToUsed(nameServer);
			_fileNames.addAll(fileAsker.runAsClient(_fileManager, nameServer));
		}

		LinkedList<IPaddress> temporaryServers = new LinkedList<IPaddress>();
		
		boolean foundNewServer = false;
		
		for (IPaddress nameServer : _knownNameServers){
			temporaryServers.addAll(
					serverAsker.runAsClient(_fileManager, nameServer));
			for (IPaddress ns : temporaryServers){
				if (!_fileManager.knowsNameServer(ns)){
					foundNewServer=true;
					_fileManager.addNameServer(ns);
				}
			}
		}
		_knownNameServers = _fileManager.getNameServerList();
		if (foundNewServer){
			return run();
		}else{
			printAllFiles();
			return SUCCESS;
		}
		
	}
		
	/**
	 * 	Prints all the files received by the DirAllFiles command.
	 * prints them alphabetically ordered.
	 */
	private void printAllFiles() {
		TreeSet<String> orderedFiles = new TreeSet<String>(_fileNames);
			for (String fileName : orderedFiles){
				System.out.println(fileName);
		}
		
	}

		/**
		 * Adds a nameServer to the Used list.
		 * @param nameServer the name server to be added.
		 */
	private void addToUsed(IPaddress nameServer){
		_usedNameServers.add(nameServer);
	}
		
		
		/**
		 * Returns whether this server was already searched or not.
		 * @param nameServer the nameserver to be checked.
		 * @return true if was used, false otherwise.
		 */
		private boolean wasNameServerUsed(IPaddress nameServer){
			for (IPaddress used : _usedNameServers){
				if (nameServer.equals(used)){
					return true;
				}
			}
			return false;
		}


}
